package chapter05_string;

/**
 * 描述：前缀树
 *      字典树又称为前缀树或Trie树，是处理字符串常见的数据结构。假设组成所有单词的
 * 字符仅是“a”~“z”，请实现字典树结构，并包含以下四个主要功能：
 *      添加word（可重复）、删除word、查询word是否在字典树中、返回以pre为前缀的单词数量
 *
 * @author hl
 * @date 2021/10/4 17:20
 */
public class Trie {
    private TrieNode root;

    public Trie() {
        this.root = new TrieNode();
    }

    public boolean insert(String word){
        if (isEmpty(word)) {
            return false;
        }
        int index = 0;
        TrieNode cur = root;
        for (int i = 0; i < word.length(); i++) {
            index = word.charAt(i) - 'a';
            if (cur.map[index] == null) {
                cur.map[index] = new TrieNode();
            }
            cur = cur.map[index];
            cur.path++;
        }
        cur.end++;
        return true;
    }

    public boolean search(String word){
        if (isEmpty(word)) {
            return false;
        }
        TrieNode cur = root;
        int index = 0;
        for (int i = 0; i < word.length(); i++) {
            index = word.charAt(i) - 'a';
            if (cur.map[index] == null) {
                break;
            }
            cur = cur.map[index];
        }
        return cur.end != 0;
    }

    public void delete(String word){
        if (!search(word)) {
            return;
        }
        TrieNode cur = root;
        int index = 0;
        for (int i = 0; i < word.length(); i++) {
            index = word.charAt(i) - 'a';
            //当前的结点的path-1后为0，那么表示后序路径只有当前word在使用，可以直接断开后序路径
            if (cur.map[index].path-- == 1) {
                cur.map[index] = null;
                return ;
            }
            cur = cur.map[index];
        }
        cur.end--;
    }

    public int prefixNumber(String word){
        if (isEmpty(word)) {
            return 0;
        }
        TrieNode cur = root;
        int index = 0;
        for (int i = 0; i < word.length(); i++) {
            index = word.charAt(i) - 'a';
            if (cur.map[index] == null) {
                return 0;
            }
            cur = cur.map[index];
        }
        return cur.path;
    }


    public boolean isEmpty(String word){
        return word == null || word.length() == 0;
    }



    public class TrieNode{
        //path表示有多少个单词公用此结点
        public int path;
        //end表示有多少个单词以此单词结尾
        public int end;
        //表示key表示当前结点的下一个路径，value表示对应的结点
        public TrieNode[] map;

        public TrieNode() {
            path = 0;
            end = 0;
            map = new TrieNode[26];//只包含a-z
        }
    }
}
